﻿namespace Eldert.BTUG.IoT.Device.Simulation
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Xml.Linq;

    using Libraries.Extensions;

    /// <summary>
    /// Class use to manage settings.
    /// </summary>
    internal class SettingsManagement
    {
        /// <summary>
        /// Collection which will keep track of current settings.
        /// </summary>
        private static readonly Dictionary<string, string> settings = new Dictionary<string, string>();

        /// <summary>
        /// Settings file name.
        /// </summary>
        private const string SETTINGS_XML = "Settings.xml";

        /// <summary>
        /// Update a application setting.
        /// </summary>
        /// <param name="name">Name of the setting.</param>
        /// <param name="value">New value to be assigned to the setting.</param>
        internal static void UpdateSetting(string name, string value)
        {
            try
            {
                // Update setting
                Console.WriteLine($"Old setting: {name} - {GetSetting(name)}");
                SetSetting(name, value);
                Console.WriteLine($"New setting: {name} - {GetSetting(name)}");
            }
            catch (Exception exception)
            {
                exception.Log();
            }
        }

        /// <summary>
        /// Check for messages from IoT Hub with updated settings.
        /// </summary>
        internal static async void CheckForUpdatedSettings()
        {
            // Keep checking
            while (true)
            {
                // Receive updated settings from IoT Hub
                var updatedSetting = await IoTHubProxy.Receive();

                // Check if valid setting was received
                if (!string.IsNullOrWhiteSpace(updatedSetting) && updatedSetting.Split(';').Length == 2)
                {
                    // Update the setting
                    UpdateSetting(updatedSetting.Split(';')[0], updatedSetting.Split(';')[1]);
                }
            }
            // ReSharper disable once FunctionNeverReturns
        }

        /// <summary>
        /// Get the value of a setting.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        internal static string GetSetting(string name)
        {
            // Check if setting is already loaded
            if (!settings.ContainsKey(name))
            {
                // Load setting
                settings.Add(
                    name,
                    XDocument.Load(SETTINGS_XML)
                        .Elements("Settings")
                        .SelectMany(element => element.Elements("Setting"))
                        .FirstOrDefault(element => element.Attribute("Name").Value == name)?.Attribute("Value")
                        .Value);
            }

            return settings[name];
        }

        /// <summary>
        /// Get the value of a setting.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private static void SetSetting(string name, string value)
        {
            var document = XDocument.Load(SETTINGS_XML);

            try
            {
                settings[name] = value;
                document.Elements("Settings")
                    .SelectMany(element => element.Elements("Setting"))
                    .FirstOrDefault(element => element.Attribute("Name").Value == name)?
                    .Attribute("Value")
                    .SetValue(value);
                //document.Save(new FileStream(SETTINGS_XML, FileMode.Open));
            }
            catch (Exception exception)
            {
                exception.Log();
            }
        }
    }
}